package com.biotools.meerkat;

import java.util.Random;

public class Deck
{
    public static final int NUM_CARDS = 52;
    private Random r;
    private Card[] gCards;
    private int[] cardMap;
    private int position;
    
  
    public Deck() {
        super();
        this.r = new Random();
        this.gCards = new Card[52];
        this.cardMap = new int[52];
        this.position = 0;
        for (int i = 0; i < 52; ++i) {
            this.gCards[i] = new Card(i);
            this.cardMap[i] = i;
        }
    }
    
    public void copy(final Deck d) {
        System.arraycopy(d.gCards, 0, this.gCards, 0, 52);
        System.arraycopy(d.cardMap, 0, this.cardMap, 0, 52);
        this.position = d.position;
    }
    
    public Deck(final long seed) {
        this();
        this.setSeed(seed);
    }
    
    public void setSeed(final long seed) {
        if (seed != 0L) {
            (this.r = new Random()).setSeed(seed);
        }
    }
    
    public void reset() {
        this.position = 0;
    }
    
    public void shuffle() {
        for (int i = 0; i < 52; ++i) {
            final int j = i + this.r.nextInt(52 - i);
            final Card tempCard = this.gCards[j];
            this.gCards[j] = this.gCards[i];
            this.gCards[i] = tempCard;
            this.cardMap[this.gCards[i].getIndex()] = i;
            this.cardMap[this.gCards[j].getIndex()] = j;
        }
        this.position = 0;
    }
    
    public Card deal() {
        return (this.position < 52) ? this.gCards[this.position++] : null;
    }
    
    public Card dealCard() {
        return this.extractRandomCard();
    }
    
    public int findCard(final Card c) {
        return this.cardMap[c.getIndex()];
    }
    
    public int findCard(final int c_index) {
        return this.cardMap[c_index];
    }
    
    public int findDiscard(final Card c) {
        return this.findDiscard(c.getIndex());
    }
    
    public int findDiscard(final int c_index) {
        return this.cardMap[c_index];
    }
    
    public boolean inDeck(final Card c) {
        return this.cardMap[c.getIndex()] >= this.position;
    }
    
    public void extractHand(final Hand h) {
        for (int i = 1; i <= h.size(); ++i) {
            if (h.getCardIndex(i) >= 0) {
                this.extractCard(h.getCardIndex(i));
            }
        }
    }
    
    public void extractCard(final int c_index) {
        final int i = this.findCard(c_index);
        if (i != -1) {
            final Card t = this.gCards[i];
            this.gCards[i] = this.gCards[this.position];
            this.gCards[this.position] = t;
            this.cardMap[this.gCards[i].getIndex()] = i;
            this.cardMap[t.getIndex()] = this.position;
            ++this.position;
        }
        else {
            assert false;
        }
    }
    
    public void extractCard(final Card c) {
        this.extractCard(c.getIndex());
    }
    
    public Card extractRandomCard() {
        final int pos = this.position + this.r.nextInt(52 - this.position);
        final Card c = this.gCards[pos];
        this.gCards[pos] = this.gCards[this.position];
        this.gCards[this.position] = c;
        this.cardMap[this.gCards[pos].getIndex()] = pos;
        this.cardMap[c.getIndex()] = this.position;
        ++this.position;
        return c;
    }
    
    public Card pickRandomCard() {
        return this.gCards[this.position + this.r.nextInt(52 - this.position)];
    }
    
    public void replaceCard(final Card c) {
        this.replaceCard(c.getIndex());
    }
    
    public void replaceCard(final int c_index) {
        final int i = this.findDiscard(c_index);
        if (i != -1) {
            --this.position;
            final Card t = this.gCards[i];
            this.gCards[i] = this.gCards[this.position];
            this.gCards[this.position] = t;
            this.cardMap[this.gCards[i].getIndex()] = i;
            this.cardMap[t.getIndex()] = this.position;
        }
    }
    
    public int getTopCardIndex() {
        return this.position;
    }
    
    public Card getTopCard() {
        return this.getCard(this.position);
    }
    
    public int cardsLeft() {
        return 52 - this.position;
    }
    
    public final Card getCard(final int i) {
        return this.gCards[i];
    }
    
    public String toString() {
        final StringBuffer s = new StringBuffer();
        s.append("* ");
        for (int i = 0; i < this.position; ++i) {
            s.append(String.valueOf(this.gCards[i].toString()) + " ");
        }
        s.append("\n* ");
        for (int i = this.position; i < 52; ++i) {
            s.append(String.valueOf(this.gCards[i].toString()) + " ");
        }
        return s.toString();
    }
}
